package cn.golxen.rsms.service.impl;

import cn.golxen.rsms.bean.bo.*;
import cn.golxen.rsms.bean.entity.*;
import cn.golxen.rsms.bean.vo.ResFrequentPurchaseGoodsAnalysisVo;
import cn.golxen.rsms.bean.vo.ResGoodsInfoVo;
import cn.golxen.rsms.bean.vo.ResGoodsSalesAnalysisVo;

import cn.golxen.rsms.commons.utils.LocalDateTimeUtils;
import cn.golxen.rsms.commons.utils.YmlUtils;
import cn.golxen.rsms.exception.exceptionClass.AddGoodsStoreException;
import cn.golxen.rsms.exception.exceptionClass.GetBarcodeInfoException;
import cn.golxen.rsms.exception.exceptionClass.GetGoodsInfoException;
import cn.golxen.rsms.exception.exceptionClass.ImportExcelException;
import cn.golxen.rsms.mapper.GoodsMapper;
import cn.golxen.rsms.mapper.LogMapper;
import cn.golxen.rsms.mapper.StoreMapper;
import cn.golxen.rsms.redis.GoodsRedis;
import cn.golxen.rsms.redis.RedisUtils;
import cn.golxen.rsms.service.GoodsService;
import cn.golxen.rsms.service.LogService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.text.DecimalFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class GoodsServiceImpl implements GoodsService {

    @Autowired
    LogService logService;
    @Autowired
    GoodsMain goodsMain;
    @Autowired
    GoodsStore goodsStore;
    @Autowired
    GoodsMapper goodsMapper;
    @Autowired
    LogMapper logMapper;
    //    @Autowired
//    RedisUtils redisUtils;
    @Autowired
    GoodsRedis goodsRedis;
    @Autowired
    StoreMapper storeMapper;
    @Autowired
    @Qualifier(value = "taskExecutor")
    private ThreadPoolTaskExecutor poolTaskExecutor;

    @Autowired
    @Qualifier(value = "clientExample")
    private OSS ossClient;

    @Override
    public GoodsMain getBarcodeInfo(String code) {
        return goodsRedis.getBarcodeInfo(code);
    }

    @Override
    public List<GoodsMain> getGoodsMainList(List<String> codeList) {
        return goodsMapper.getGoodsMainList(codeList);
    }


    @Override
    public ResGoodsInfoVo getGoodsInfo(String code, int storeId) {
        log.info("基于商店获取商品信息");
        try {
            return goodsMapper.getGoodsInfo(code, storeId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new GetGoodsInfoException();
        }

    }

    @Override
    public ResGoodsInfoVo getGoodsInfo2(String code, int storeId) {
        log.info("基于商店获取商品信息");
        try {
            goodsStore = goodsMapper.getGoodsStore(storeId, code);
            if (goodsStore == null)
                return null;
            ResGoodsInfoVo resGoodsInfoVo = new ResGoodsInfoVo();
            resGoodsInfoVo.setGoodsName(goodsStore.getGoodsName());
            resGoodsInfoVo.setCode(goodsStore.getCode());
            resGoodsInfoVo.setCreationDate(goodsStore.getCreationDate());
            resGoodsInfoVo.setInventory(goodsStore.getInventory());
            resGoodsInfoVo.setCost(goodsStore.getCost());
            resGoodsInfoVo.setPrice(goodsStore.getPrice());
            resGoodsInfoVo.setRecentSales(goodsStore.getRecentSales());
            resGoodsInfoVo.setWarn(goodsStore.getWarn());
            resGoodsInfoVo.setStoreId(goodsStore.getStoreId());
            resGoodsInfoVo.setState(goodsStore.getState());

            try {
                GoodsMain goodsMain = goodsRedis.getBarcodeInfo(goodsStore.getCode());
                resGoodsInfoVo.setGoodsType(goodsMain.getGoodsType());
                resGoodsInfoVo.setImage(goodsMain.getImage());
            } catch (GetBarcodeInfoException e) {
                resGoodsInfoVo.setGoodsType("其他");
                resGoodsInfoVo.setImage("'http://bt.golxen.cn:15357/down/ijnXgaRVvBU5'");
            }
            return resGoodsInfoVo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GetGoodsInfoException();
        }

    }


    @Override
    public List<ResGoodsInfoVo> getGoodsInfoList(int storeId) {
        return goodsMapper.getGoodsInfoList(storeId);
    }

    @Override
    public List<ResGoodsInfoVo> getGoodsInfoList2(int storeId) {
        List<GoodsStore> goodsStoreList = goodsMapper.getGoodsInfoList2(storeId);
        List<ResGoodsInfoVo> goodsInfoList2 = new LinkedList<>();
        for (GoodsStore goodsStore : goodsStoreList) {
            ResGoodsInfoVo resGoodsInfoVo = new ResGoodsInfoVo();
            resGoodsInfoVo.setGoodsName(goodsStore.getGoodsName());
            resGoodsInfoVo.setCode(goodsStore.getCode());
            resGoodsInfoVo.setCreationDate(goodsStore.getCreationDate());
            resGoodsInfoVo.setInventory(goodsStore.getInventory());
            resGoodsInfoVo.setCost(goodsStore.getCost());
            resGoodsInfoVo.setPrice(goodsStore.getPrice());
            resGoodsInfoVo.setRecentSales(goodsStore.getRecentSales());
            resGoodsInfoVo.setWarn(goodsStore.getWarn());
            resGoodsInfoVo.setStoreId(goodsStore.getStoreId());
            resGoodsInfoVo.setState(goodsStore.getState());
            try {
                GoodsMain goodsMain = goodsRedis.getBarcodeInfo(goodsStore.getCode());
                resGoodsInfoVo.setGoodsType(goodsMain.getGoodsType());
                resGoodsInfoVo.setImage(goodsMain.getImage());
            } catch (GetBarcodeInfoException e) {
                resGoodsInfoVo.setGoodsType("其他");
                resGoodsInfoVo.setImage("'http://bt.golxen.cn:15357/down/ijnXgaRVvBU5'");
            }
            goodsInfoList2.add(resGoodsInfoVo);

        }

        return goodsInfoList2;
    }

    @Override
    public List<String> getGoodsCodeList(int storeId) {
        return goodsMapper.getGoodsCodeList(storeId);
    }

    @Override
    public List<ResGoodsInfoVo> getGoodsInfoListByCodeList(List<String> codeList, int storeId) {
        List<GoodsStore> goodsStoreList = goodsMapper.getGoodsStoreList(codeList, storeId);
        List<ResGoodsInfoVo> goodsInfoList2 = new LinkedList<>();
        for (GoodsStore goodsStore : goodsStoreList) {
            ResGoodsInfoVo resGoodsInfoVo = new ResGoodsInfoVo();
            resGoodsInfoVo.setGoodsName(goodsStore.getGoodsName());
            resGoodsInfoVo.setCode(goodsStore.getCode());
            resGoodsInfoVo.setCreationDate(goodsStore.getCreationDate());
            resGoodsInfoVo.setInventory(goodsStore.getInventory());
            resGoodsInfoVo.setCost(goodsStore.getCost());
            resGoodsInfoVo.setPrice(goodsStore.getPrice());
            resGoodsInfoVo.setRecentSales(goodsStore.getRecentSales());
            resGoodsInfoVo.setWarn(goodsStore.getWarn());
            resGoodsInfoVo.setStoreId(goodsStore.getStoreId());
            resGoodsInfoVo.setState(goodsStore.getState());

            try {
                GoodsMain goodsMain = goodsRedis.getBarcodeInfo(goodsStore.getCode());
                resGoodsInfoVo.setGoodsType(goodsMain.getGoodsType());
                resGoodsInfoVo.setImage(goodsMain.getImage());
            } catch (GetBarcodeInfoException e) {
                resGoodsInfoVo.setGoodsType("其他");
                resGoodsInfoVo.setImage("'http://bt.golxen.cn:15357/down/ijnXgaRVvBU5'");
            }
            goodsInfoList2.add(resGoodsInfoVo);

        }

        return goodsInfoList2;
    }

    @Override
    public List<ResGoodsInfoVo> getGoodsInfoListByType(String type, int storeId) {
        return goodsMapper.getGoodsInfoListByType(type, storeId);
    }

    @Override
    public Double getSuggestedPrice(String code) {
        return goodsMapper.getSuggestedPrice(code);
    }

    @Override
    public int addGoodsStore(List<GoodsStore> goodsStoreList) {
        log.info("基于商店添加商品信息");
        try {
            for (GoodsStore goodsStore1 : goodsStoreList) {
                try {
                    //通过条形码从数据库获取商品信息，如果数据库没有相关信息则去中国编码中心获取
                    goodsMain = goodsRedis.getBarcodeInfo(goodsStore1.getCode());
                } catch (GetBarcodeInfoException e) {
                    //如果编码中心也没有相关商品则系为本商店独有的商品
                    LocalDateTime localDateTime = LocalDateTimeUtils.getLocalDateTime();
                    goodsStore1.setCreationDate(localDateTime);
                    if (goodsStore1.getInventory() <= goodsStore1.getWarn())
                        goodsStore1.setState(1);
                }
                //判断商家是否自定义商品名，否则采用商品默认名称
                if (goodsStore1.getGoodsName() == null || goodsStore1.getGoodsName().equals("")) {
                    if (goodsMain.getGoodsName() != null)
                        goodsStore1.setGoodsName(goodsMain.getGoodsName());
                    else goodsStore1.setGoodsName("");

                }
                LocalDateTime localDateTime = LocalDateTimeUtils.getLocalDateTime();
                goodsStore1.setCreationDate(localDateTime);
                //判断是否低于预设的库存，是则为紧缺库存
                if (goodsStore1.getInventory() <= goodsStore1.getWarn())
                    goodsStore1.setState(1);
            }

            return goodsMapper.addGoodsStoreList(goodsStoreList);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AddGoodsStoreException();
        }

    }

    @Override
    public int importExcel(ImportExcelBo importExcelBo) {

        try {
            // 调用ossClient.getObject返回一个OSSObject实例，该实例包含文件内容及文件元信息。
            OSSObject ossObject = ossClient.getObject(YmlUtils.getString("oss.bucket"), importExcelBo.getExcelFileName());
            // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
            InputStream content = ossObject.getObjectContent();
            if (content != null) {
                List<GoodsStore> goodsStoreList = EasyExcel.read(content).head(GoodsStore.class).sheet().doReadSync();
//                log.info(com.alibaba.fastjson.JSONObject.toJSONString(goodsStoreList));
                // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
                content.close();
                for (GoodsStore store : goodsStoreList) {
                    try {
                        goodsMain = goodsRedis.getBarcodeInfo(store.getCode());
                        if (store.getGoodsName() == null || store.getGoodsName().equals(""))
                            store.setGoodsName(goodsMain.getGoodsName());

                    } catch (GetBarcodeInfoException e) {
                        log.info(store.toString() + "------新增goodsMain失败");
//                        goodsStoreList.remove(store);
//                        API里没有也不一定就不录入 也是可以扫出来的
                    }
                    store.setStoreId(importExcelBo.getStoreId());
                    store.setCreationDate(LocalDateTimeUtils.getLocalDateTime());
                    store.setInventory(Integer.parseInt(store.getInventoryStr()));
                    store.setCost(Double.parseDouble(store.getCostStr()));
                    store.setPrice(Double.parseDouble(store.getPriceStr()));
                    store.setWarn(Integer.parseInt(store.getWarnStr()));
//                    log.info(store.toString());
                }

                List<String> codeList = new LinkedList<>();
                Map<String, Integer> inventoryMap = new HashMap<>();
                for (GoodsStore goodsStore : goodsStoreList) {
                    if (goodsStore.getInventory() > goodsStore.getWarn()) {
                        codeList.add(goodsStore.getCode());
                        inventoryMap.put(goodsStore.getCode(), goodsStore.getInventory());
                    } else
                        goodsStore.setState(1);
                }
                Map<String, Integer> stateMap = new HashMap<>();
                if (codeList.size() > 0)
                    stateMap = judgeWarnByInventory(codeList, inventoryMap, goodsStoreList.get(0).getStoreId());
                for (GoodsStore goodsStore : goodsStoreList) {
                    if (stateMap.get(goodsStore.getCode()) != null)
                        goodsStore.setState(stateMap.get(goodsStore.getCode()));
                }

                int i = goodsMapper.addGoodsStoreList(goodsStoreList);
                if (i > 0) {
                    poolTaskExecutor.execute(() -> {
//                        LogService logService=new LogServiceImpl();
                        logService.addGoodsLogListByObject(goodsStoreList, "新建商品入库");
                    });
                }
                return i;
            }
            // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
            content.close();
            return 0;


        } catch (Exception e) {
            e.printStackTrace();
            throw new ImportExcelException();
        }

    }

    @Override
    public int updateGoodsMainSuggestedPrice(String code) {

        return goodsRedis.updateGoodsMainSuggestedPrice(code);
    }

    @Override
    public int addGoodsTypeNx(String type) {
        if (goodsMapper.isExGoodsTypeByType(type) == null) {
            return goodsMapper.addGoodsType(type);
        }
        return 0;
    }

    @Override
    public List<GoodsType> getGoodsTypeList() {

        return goodsRedis.getGoodsTypeList();

    }

    @Override
    public int delGoodsStoreList(DelGoodsStoreBo delGoodsStoreBo) {
        return goodsMapper.delGoodsStoreList(delGoodsStoreBo);
    }

    @Override
    public int updateGoodsStore(List<GoodsStore> goodsStoreList) {
        List<String> codeList = new LinkedList<>();
        Map<String, Integer> inventoryMap = new HashMap<>();
        for (GoodsStore goodsStore : goodsStoreList) {
            if (goodsStore.getInventory() > goodsStore.getWarn()) {
                codeList.add(goodsStore.getCode());
                inventoryMap.put(goodsStore.getCode(), goodsStore.getInventory());
            } else
                goodsStore.setState(1);
        }
        Map<String, Integer> stateMap = new HashMap<>();
        if (codeList.size() > 0)
            stateMap = judgeWarnByInventory(codeList, inventoryMap, goodsStoreList.get(0).getStoreId());
        for (GoodsStore goodsStore : goodsStoreList) {
            if (stateMap.get(goodsStore.getCode()) != null)
                goodsStore.setState(stateMap.get(goodsStore.getCode()));
        }
        return goodsMapper.updateGoodsStoreList(goodsStoreList, goodsStoreList.get(0).getStoreId());
    }

    @Override
    public int addGoodsNum(List<AddOrOutGoodsNumBo> addOrOutGoodsNumBoList) {

        List<String> codeList = new LinkedList<>();
        Map<String, Integer> addNumMap = new HashMap<>();
        for (AddOrOutGoodsNumBo goodsStore : addOrOutGoodsNumBoList) {
            goodsStore.setState(0);
            if (goodsStore.getInventory() + goodsStore.getNum() > goodsStore.getWarn()) {
                codeList.add(goodsStore.getCode());
                addNumMap.put(goodsStore.getCode(), goodsStore.getNum());
            } else
                goodsStore.setState(1);
        }
        Map<String, Integer> stateMap = new HashMap<>();
        if (codeList.size() > 0)
            stateMap = judgeWarnByAddNumMap(codeList, addNumMap, addOrOutGoodsNumBoList.get(0).getStoreId());
        for (AddOrOutGoodsNumBo goodsStore : addOrOutGoodsNumBoList) {
            if (stateMap.get(goodsStore.getCode()) != null)
                goodsStore.setState(stateMap.get(goodsStore.getCode()));
        }
        return goodsMapper.addGoodsInventoryList(addOrOutGoodsNumBoList, addOrOutGoodsNumBoList.get(0).getStoreId());
    }

    @Override
    public List<ResGoodsInfoVo> getGoodsInfoByNameOrCode(int store, String nameOrCode) {
        return goodsMapper.getGoodsInfoByNameOrCode(store, nameOrCode);
    }

    @Override
    public List<ResGoodsSalesAnalysisVo> getNewGoodsStore(int store) {
        DecimalFormat df = new DecimalFormat("#.00");
        List<ResGoodsSalesAnalysisVo> resGoodsSalesAnalysisVoList = new LinkedList<>();
        //获取近30天创建的商品
        List<ResGoodsInfoVo> resGoodsInfoVoList = goodsMapper.getNewGoodsStore(store);
        //获取30天的销售数据
        List<GoodsLog> goodsLogByDayList = logMapper.getGoodsLogOnSalesAnalysisByDay(30, store);
        for (ResGoodsInfoVo resGoodsInfoVo : resGoodsInfoVoList) {
            ResGoodsSalesAnalysisVo resGoodsSalesAnalysisVo = new ResGoodsSalesAnalysisVo();
            int salesNum = 0;
            int transactionsNum = 0;
            List<LocalDateTime> localDateTimes = new ArrayList<>();
            for (GoodsLog goodsLog : goodsLogByDayList) {
                if (goodsLog.getCode().equals(resGoodsInfoVo.getCode())) {
                    localDateTimes.add(goodsLog.getCreateDate());
                    salesNum += goodsLog.getNum();
                    transactionsNum += 1;
                }
            }
            double salesVolume = salesNum * resGoodsInfoVo.getPrice();
            Double gross = salesVolume - salesNum * resGoodsInfoVo.getCost();
            BeanUtils.copyProperties(resGoodsInfoVo, resGoodsSalesAnalysisVo);
            resGoodsSalesAnalysisVo.setSalesNum(salesNum);
            resGoodsSalesAnalysisVo.setSalesVolume(Double.valueOf(df.format(salesVolume)));
            resGoodsSalesAnalysisVo.setTransactionsNum(transactionsNum);
            resGoodsSalesAnalysisVo.setGross(Double.valueOf(df.format(gross)));
            if (localDateTimes.size() == 0)
                resGoodsSalesAnalysisVo.setLatestSellingTime(null);
            else
                resGoodsSalesAnalysisVo.setLatestSellingTime(localDateTimes.get(0));
            resGoodsSalesAnalysisVoList.add(resGoodsSalesAnalysisVo);
        }
        return resGoodsSalesAnalysisVoList;
    }

    @Override
    public List<ResGoodsSalesAnalysisVo> getGoodsHotSale(int store) {
        DecimalFormat df = new DecimalFormat("#.00");
        //获取近30他销售数据
        List<AnalysisGoodsBo> analysisGoodsBoList = logMapper.getGoodsLogOnSalesAnalysisByDay2(30, store);
        List<ResGoodsSalesAnalysisVo> resGoodsSalesAnalysisVoList = new LinkedList<>();
        int sumTransactionsNum = 0;
        for (AnalysisGoodsBo analysisGoodsBo : analysisGoodsBoList) {
            sumTransactionsNum += analysisGoodsBo.getTransactionsNum();
        }
        int avgTransactionsNum = sumTransactionsNum / analysisGoodsBoList.size();
        for (AnalysisGoodsBo analysisGoodsBo : analysisGoodsBoList) {
            //高于平均销售笔数即为热销
            if (analysisGoodsBo.getTransactionsNum() > avgTransactionsNum) {
                ResGoodsSalesAnalysisVo resGoodsSalesAnalysisVo = new ResGoodsSalesAnalysisVo();
                ResGoodsInfoVo resGoodsInfoVo = getGoodsInfo2(analysisGoodsBo.getCode(), store);
                if (resGoodsInfoVo == null)
                    continue;
                BeanUtils.copyProperties(resGoodsInfoVo, resGoodsSalesAnalysisVo);
                BeanUtils.copyProperties(analysisGoodsBo, resGoodsSalesAnalysisVo);
                resGoodsSalesAnalysisVo.setSalesVolume(Double.valueOf(df.format(resGoodsSalesAnalysisVo.getSalesVolume())));
                resGoodsSalesAnalysisVo.setGross(Double.valueOf(df.format(resGoodsSalesAnalysisVo.getGross())));
                resGoodsSalesAnalysisVoList.add(resGoodsSalesAnalysisVo);
            }
        }

        return resGoodsSalesAnalysisVoList;
    }

    @Override
    public List<ResGoodsSalesAnalysisVo> getGoodsUnsalable(int store) {
        DecimalFormat df = new DecimalFormat("#.00");
        List<ResGoodsInfoVo> resGoodsInfoVoList = goodsMapper.getGoodsInfoList(store);
        //获取近30天销售数据
        List<AnalysisGoodsBo> analysisGoodsBoList = logMapper.getGoodsLogOnSalesAnalysisByDay2(30, store);
        List<ResGoodsSalesAnalysisVo> resGoodsSalesAnalysisVoList = new LinkedList<>();
        LocalDateTime localDateTimeNow = LocalDateTimeUtils.getLocalDateTime();

        for (AnalysisGoodsBo analysisGoodsBo : analysisGoodsBoList) {
            //交易笔数少于2笔，销量少于3并且利润过低,并且库存过多即为滞销
            if ((analysisGoodsBo.getTransactionsNum() < 2)
                    || (analysisGoodsBo.getSalesNum() < 3 && (analysisGoodsBo.getGross() < 3 || analysisGoodsBo.getSalesVolume() / analysisGoodsBo.getGross() > 2))) {
                ResGoodsSalesAnalysisVo resGoodsSalesAnalysisVo = new ResGoodsSalesAnalysisVo();
                ResGoodsInfoVo resGoodsInfoVo = goodsMapper.getGoodsInfo(analysisGoodsBo.getCode(), store);
                if (resGoodsInfoVo != null) {
                    //非新品销量少于当前库存
                    if (resGoodsInfoVo.getInventory() > analysisGoodsBo.getSalesNum() && Duration.between(resGoodsInfoVo.getCreationDate(), localDateTimeNow).toDays() > 30) {
                        BeanUtils.copyProperties(resGoodsInfoVo, resGoodsSalesAnalysisVo);
                        BeanUtils.copyProperties(analysisGoodsBo, resGoodsSalesAnalysisVo);
                        resGoodsSalesAnalysisVoList.add(resGoodsSalesAnalysisVo);
                    }
                }


            }
            resGoodsInfoVoList.removeIf(resGoodsInfoVo -> resGoodsInfoVo.getCode().equals(analysisGoodsBo.getCode()));
        }
        for (ResGoodsInfoVo resGoodsInfoVo : resGoodsInfoVoList) {
            //非新品近30天没销量即为滞销
            if (resGoodsInfoVo.getInventory() > 0 && Duration.between(resGoodsInfoVo.getCreationDate(), localDateTimeNow).toDays() > 30) {
                ResGoodsSalesAnalysisVo resGoodsSalesAnalysisVo = new ResGoodsSalesAnalysisVo();
                BeanUtils.copyProperties(resGoodsInfoVo, resGoodsSalesAnalysisVo);

                try {
                    LocalDateTime latestSellingTime = logMapper.getLatestSellingTime(resGoodsInfoVo.getCode(), store).getCreateDate();
                    resGoodsSalesAnalysisVo.setLatestSellingTime(latestSellingTime);
                } catch (NullPointerException e) {
                    e.printStackTrace();
                } finally {
                    resGoodsSalesAnalysisVo.setSalesVolume(Double.valueOf(df.format(resGoodsSalesAnalysisVo.getSalesVolume())));
                    resGoodsSalesAnalysisVo.setGross(Double.valueOf(df.format(resGoodsSalesAnalysisVo.getGross())));
                    resGoodsSalesAnalysisVoList.add(resGoodsSalesAnalysisVo);
                }
            }

        }

        return resGoodsSalesAnalysisVoList;
    }

    @Override
    public List<ResFrequentPurchaseGoodsAnalysisVo> getFrequentPurchase(int store) {
        DecimalFormat df = new DecimalFormat("#.00");
        List<ResFrequentPurchaseGoodsAnalysisVo> resFrequentPurchaseGoodsAnalysisVoList = new LinkedList<>();
        List<GetPurchaseTimesBo> purchaseTimesBoList = logMapper.getPurchaseTimesListByDay(180, store);
        int sumPurchaseTimes = 0;
        for (GetPurchaseTimesBo purchaseTimesBo : purchaseTimesBoList) {
            sumPurchaseTimes += purchaseTimesBo.getPurchaseTimes();
        }
        int avgPurchaseTimes = sumPurchaseTimes / purchaseTimesBoList.size();
        List<String> codeList = new LinkedList<>();
        for (GetPurchaseTimesBo purchaseTimesBo : purchaseTimesBoList) {
            //获取平均进货次数以上的货物为常进货货物
            if (purchaseTimesBo.getPurchaseTimes() >= avgPurchaseTimes && purchaseTimesBo.getPurchaseTimes() != 0)
                codeList.add(purchaseTimesBo.getCode());
        }
        List<ResGoodsSalesAnalysisVo> resGoodsSalesAnalysisVoList = goodsMapper.getGoodsSalesAnalysisByDayAndCodeList(180, codeList, store);
        for (GetPurchaseTimesBo purchaseTimesBo : purchaseTimesBoList) {
            ResFrequentPurchaseGoodsAnalysisVo resVo = new ResFrequentPurchaseGoodsAnalysisVo();
            BeanUtils.copyProperties(purchaseTimesBo, resVo);
            for (ResGoodsSalesAnalysisVo resGoodsSalesAnalysisVo : resGoodsSalesAnalysisVoList) {
                if (Objects.equals(resGoodsSalesAnalysisVo.getCode(), purchaseTimesBo.getCode()))
                    BeanUtils.copyProperties(resGoodsSalesAnalysisVo, resVo);
            }
            LocalDateTime latestSellingTime = null;
            if (purchaseTimesBo.getPurchaseTimes() >= avgPurchaseTimes && purchaseTimesBo.getPurchaseTimes() != 0) {
                if (resVo.getGoodsName() == null) {
                    ResGoodsInfoVo goodsInfoVo=goodsMapper.getGoodsInfo(resVo.getCode(), store);
                    if (goodsInfoVo==null)
                        continue;
                    BeanUtils.copyProperties(goodsInfoVo, resVo);
                    try {
                        latestSellingTime = logMapper.getLatestSellingTime(resVo.getCode(), store).getCreateDate();
                    } catch (NullPointerException e) {
                        e.printStackTrace();
                        log.info(purchaseTimesBo.getCode() + "无销售记录");
                    }
                    resVo.setLatestSellingTime(latestSellingTime);
                }
                resVo.setSalesVolume(Double.valueOf(df.format(resVo.getSalesVolume())));
                resVo.setSalesVolume(Double.valueOf(df.format(resVo.getGross())));
                resFrequentPurchaseGoodsAnalysisVoList.add(resVo);
            }
        }
        return resFrequentPurchaseGoodsAnalysisVoList;
    }

    @Override
    public int outGoodsNum(List<AddOrOutGoodsNumBo> addOrOutGoodsNumBoList) {
//        List<GoodsStore> goodsStoreList=new LinkedList<>();
//        for (AddOrOutGoodsNumBo addOrOutGoodsNumBo : addOrOutGoodsNumBoList){
//            int inventory= addOrOutGoodsNumBo.getInventory()- addOrOutGoodsNumBo.getNum();
//            BeanUtils.copyProperties(addOrOutGoodsNumBo,goodsStore);
//            goodsStore.setInventory(inventory);
//            goodsStoreList.add(goodsStore);
//        }
//        return goodsMapper.updateGoodsStoreList(goodsStoreList, addOrOutGoodsNumBoList.get(0).getStoreId());
        //减少商品库存传入的num为负数
        List<AddOrOutGoodsNumBo> addOrOutGoodsNumBoList2 = new LinkedList<>();
        for (AddOrOutGoodsNumBo addOrOutGoodsNumBo : addOrOutGoodsNumBoList) {
            int num = addOrOutGoodsNumBo.getNum();
            AddOrOutGoodsNumBo addOrOutGoodsNumBo2 = new AddOrOutGoodsNumBo();
            BeanUtils.copyProperties(addOrOutGoodsNumBo, addOrOutGoodsNumBo2);
            addOrOutGoodsNumBo2.setNum(-num);
            addOrOutGoodsNumBoList2.add(addOrOutGoodsNumBo2);
        }

        //判断是否红点通知
        int isNotice = 0;

        List<String> codeList = new LinkedList<>();
        Map<String, Integer> addNumMap = new HashMap<>();
        //判断库存是否低于预警值
        for (AddOrOutGoodsNumBo goodsStore : addOrOutGoodsNumBoList2) {
            goodsStore.setState(0);
            if (goodsStore.getInventory() + goodsStore.getNum() > goodsStore.getWarn()) {
                codeList.add(goodsStore.getCode());
                addNumMap.put(goodsStore.getCode(), goodsStore.getNum());
            } else {
                if (goodsStore.getState() != 1) {
                    goodsStore.setState(1);
                    isNotice = 1;
                }
            }
        }
        Map<String, Integer> stateMap = new HashMap<>();
        //如果不低于预警值则进行可售卖天数的判断，进一步确定是否属于预警库存
        if (codeList.size() > 0)
            stateMap = judgeWarnByAddNumMap(codeList, addNumMap, addOrOutGoodsNumBoList.get(0).getStoreId());
        for (AddOrOutGoodsNumBo goodsStore : addOrOutGoodsNumBoList2) {
            if (stateMap.get(goodsStore.getCode()) != null)
                if (goodsStore.getState() != 1 && stateMap.get(goodsStore.getCode()) == 1) {
                    goodsStore.setState(stateMap.get(goodsStore.getCode()));
                    isNotice = 1;
                }

        }
        if (isNotice == 1) {
            int finalIsNotice = isNotice;
            poolTaskExecutor.execute(() -> {
                storeMapper.updateWarnNotice(finalIsNotice, addOrOutGoodsNumBoList2.get(0).getStoreId());
            });
        }

        return goodsMapper.addGoodsInventoryList(addOrOutGoodsNumBoList2, addOrOutGoodsNumBoList2.get(0).getStoreId());
    }

    @Override
    public int addGoodsPurchase(GoodsPurchase goodsPurchase) {
        //将进货单详情转为json字符串存储
        goodsPurchase.setOrderDetailString(JSONObject.toJSONString(goodsPurchase.getOrderDetailObject()));
//        List<AddOrOutGoodsNumBo> addOrOutGoodsNumBoList=JSONObject.parseObject(goodsPurchase.getOrderDetailString(),List.class);
//        log.info(addOrOutGoodsNumBoList.toString());
        goodsPurchase.setUpdateTime(LocalDateTimeUtils.getLocalDateTime());
        return goodsMapper.addGoodsPurchase(goodsPurchase);
    }

    @Override
    public int delGoodsPurchase(List<Integer> ids) {
        return goodsMapper.delGoodsPurchase(ids);
    }

    @Override
    public int updateGoodsPurchase(GoodsPurchase goodsPurchase) {
        goodsPurchase.setOrderDetailString(JSONObject.toJSONString(goodsPurchase.getOrderDetailObject()));
        goodsPurchase.setUpdateTime(LocalDateTimeUtils.getLocalDateTime());
        return goodsMapper.updateGoodsPurchase(goodsPurchase);
    }

    @Override
    public List<GoodsPurchase> getGoodsPurchase(int isDone, int storeId) {
        List<GoodsPurchase> goodsPurchaseList = goodsMapper.getGoodsPurchase(isDone, storeId);
        if (goodsPurchaseList != null) {
            for (GoodsPurchase goodsPurchase : goodsPurchaseList) {
                goodsPurchase.setOrderDetailObject(JSONObject.parseObject(goodsPurchase.getOrderDetailString(), List.class));
            }
        }

        return goodsPurchaseList;
    }


    @Override
    public int oneKeyAddGoodsNum(GoodsPurchase goodsPurchase) {
        List<String> codeList = new LinkedList<>();
        Map<String, Integer> addNumMap = new HashMap<>();
        List<AddOrOutGoodsNumBo> addOrOutGoodsNumBoList = goodsPurchase.getOrderDetailObject();
        for (AddOrOutGoodsNumBo goodsStore : addOrOutGoodsNumBoList) {
            if (goodsStore.getInventory() + goodsStore.getNum() > goodsStore.getWarn()) {
                codeList.add(goodsStore.getCode());
                addNumMap.put(goodsStore.getCode(), goodsStore.getNum());
            } else
                goodsStore.setState(1);
        }
        Map<String, Integer> stateMap = new HashMap<>();
        if (codeList.size() > 0)
            stateMap = judgeWarnByAddNumMap(codeList, addNumMap, addOrOutGoodsNumBoList.get(0).getStoreId());
        for (AddOrOutGoodsNumBo goodsStore : addOrOutGoodsNumBoList) {
            if (stateMap.get(goodsStore.getCode()) != null)
                goodsStore.setState(stateMap.get(goodsStore.getCode()));
        }
        return goodsMapper.addGoodsInventoryList(addOrOutGoodsNumBoList, goodsPurchase.getStoreId());
    }

    @Override
    public List<BusinessBigDataSelectionBo> getGoodsMainListOnBigDataSelection() {
        return goodsMapper.getGoodsMainListOnBigDataSelection();
    }

    @Override
    public List<ResGoodsSalesAnalysisVo> getGoodsSalesAnalysisByPeriod(BusinessDateBo bo) {
        return goodsMapper.getGoodsSalesAnalysisByPeriod(bo);
    }

    @Override
    public List<BusinessPriceAdjustSuggestBo> getGoodsStoreAndSuggestedPrice(int storeId) {
        return goodsMapper.getGoodsStoreAndSuggestedPrice(storeId);
    }

    @Override
    public int delStore(int storeId) {
        return goodsMapper.delStore(storeId);
    }

    private Map<String, Integer> judgeWarn(List<String> codeList, int storeId) {
        Map<String, Integer> stateMap = new HashMap<>();
        List<GetGoodsWarnStateBo> goodsSalesDaysBoList = logService.getGoodsSalesDaysByLogDayAndCode(15, codeList, storeId);

        for (GetGoodsWarnStateBo temp : goodsSalesDaysBoList) {
            int state = 0;
            //实时库存s<=3即触发
            //预测可售卖天数<=3天即触发
            //可售卖天数=实际库存/近15天日均销量
            if (temp.getSalesDays() <= 3) {
                state = 1;
            }
            stateMap.put(temp.getCode(), state);
        }
        return stateMap;

    }

    private Map<String, Integer> judgeWarnByInventory(List<String> codeList, Map<String, Integer> inventoryMap, int storeId) {
        Map<String, Integer> stateMap = new HashMap<>();
        //调用日志服务获取相关销售数据
        List<GetGoodsWarnStateBo> goodsSalesDaysBoList = logService.getGoodsSalesDaysByLogDayAndCode(15, codeList, storeId);

        for (GetGoodsWarnStateBo temp : goodsSalesDaysBoList) {
            int state = 0;
            int salesDays = 0;
            //实时库存s<=3即触发
            //预测可售卖天数<=3天即触发
            //可售卖天数=实际库存/近15天日均销量
            salesDays = (int) ((inventoryMap.get(temp.getCode())) / ((double) temp.getInventory() / temp.getSalesDays()));
            if (salesDays <= 3) {
                state = 1;
            }
            stateMap.put(temp.getCode(), state);
        }
        return stateMap;

    }

    private Map<String, Integer> judgeWarnByAddNumMap(List<String> codeList, Map<String, Integer> addNumMap, int storeId) {
        Map<String, Integer> stateMap = new HashMap<>();
        List<GetGoodsWarnStateBo> goodsSalesDaysBoList = logService.getGoodsSalesDaysByLogDayAndCode(15, codeList, storeId);

        for (GetGoodsWarnStateBo temp : goodsSalesDaysBoList) {
            int state = 0;
            int salesDays = 0;
            //实时库存s<=3即触发
            //预测可售卖天数<=3天即触发
            //可售卖天数=实际库存/近15天日均销量
            salesDays = (int) ((temp.getInventory() + addNumMap.get(temp.getCode())) / ((double) temp.getInventory() / temp.getSalesDays()));
            if (salesDays <= 3) {
                state = 1;
            }
            stateMap.put(temp.getCode(), state);
        }
        return stateMap;

    }

}

